package eval.engine.cplex.InitialCplexCode;

import ilog.concert.IloException;
import ilog.concert.IloIntMap;
import ilog.concert.IloNumMap;
import ilog.cplex.IloCplex;
import ilog.opl.IloOplDataSource;
import ilog.opl.IloOplErrorHandler;
import ilog.opl.IloOplFactory;
import ilog.opl.IloOplModel;
import ilog.opl.IloOplModelDefinition;
import ilog.opl.IloOplModelSource;
import ilog.opl.IloOplSettings;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;

import org.omg.CORBA.Environment;

import eval.engine.IPlacement;
import eval.engine.cplex.CplexPlacement;
import eval.utilities.configuration.Configuration;
import eval.utilities.configuration.ExperimentConfiguration;

/**
 * @author Yosef Moatti
 * 
 * moatti@il.ibm.com
 *         
 */
public class CplexPlacementModel {
	private ExperimentConfiguration conf = ExperimentConfiguration.getSingleton();
	int nbVms;
	int nbHosts;
	
	final static Class<CplexPlacementModel> sCLASS = CplexPlacementModel.class;
	final static String CLASSNAME = sCLASS.getName(); 
	final static Logger sLOGGER = Logger.getLogger("vsilogger.debug");
	private static int fileIndex = 0;

	final protected IloOplFactory oplFactory;
	protected IloCplex cplexSolver;
	protected IloOplErrorHandler errHandler;
	final protected CplexErrorLogger errLogger;
	protected IloOplModel model;
	
	private static final String CPLEX_OPT_PARAM_PREFIX = "vsi.config.cplex.optParam.";
	
	int[][] vmOnHostMap;
	protected Environment environment;
	protected IloOplDataSource dataSource;

	// counts the number of times the method createNewModel is invoked
	private int modelCount = 0;

	/**
	 * @param cplexInputString each line of this string defines one of the OPL input
	 */
	public CplexPlacementModel(String cplexInputString,int nbVms,int nbHosts) {
		IloOplFactory.setDebugMode(CplexAdapter.COLLECT_CPLEX_FILES_TO_FILE);  // used also as meaning that DEBUG CPLEX should be set 
		oplFactory = new IloOplFactory();
		
		this.errLogger = new CplexErrorLogger();
		this.errHandler = oplFactory.createOplErrorHandler(errLogger);

		// The index is used so that each call to the solver has a unique file.
		// Investigation should be done to determine if files need to be closed.
		fileIndex = fileIndex + 1;
		this.nbVms = nbVms;
		this.nbHosts = nbHosts;
		try {
			cplexSolver = oplFactory.createCplex();
			cplexSolver.setParam(IloCplex.IntParam.ParallelMode, -1); // Parallel alg. of CPLEX used

//			Properties cplextParams = getCplexParams();
//			setCplexParams(cplextParams);
		} catch (IloException e) {
			e.printStackTrace();
		}

		createNewModel();

		dataSource = new CplexDataSource(oplFactory, cplexInputString);
			
		if (!((CplexDataSource)dataSource).isUseCplexJNI()) {
			// the input to CPLEX was requested to be sent as a .dat file:
			((CplexDataSource)dataSource).customRead();
			String latestFileName = ((CplexDataSource)dataSource).generateNewDataFileName(); 
			IloOplDataSource fileDataSource = oplFactory.createOplDataSourceFromString(((CplexDataSource)dataSource).getDataString(), latestFileName);
			dataSource = fileDataSource;
		}  

		model.addDataSource(dataSource);
	}

	public void createNewModel() {

		if (model != null) {
			model.resetSolutionGetter();
			model.delete();
		}

		IloOplModelSource modelSource = oplFactory
				.createOplModelSourceFromString(getModelStringRepresentation(), Integer.toString(modelCount));

		IloOplSettings settings = oplFactory.createOplSettings(errHandler);
		IloOplModelDefinition modelDefinition = oplFactory.createOplModelDefinition(modelSource, settings);
		model = oplFactory.createOplModel(modelDefinition, cplexSolver);

		modelCount++;
	}

	protected String getModelStringRepresentation() {

		StringBuffer stringBuffer = new StringBuffer(1000);

		try {
			InputStream inputStream = getClass().getResourceAsStream("oplUnivModel.mod");

			BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));

			int numRead = 0;
			char[] buf = new char[1024];
			while ((numRead = br.read(buf)) != -1) {
				String readData = String.valueOf(buf, 0, numRead);
				stringBuffer.append(readData);
				buf = new char[1024];
			}
			br.close();

		} catch (IOException e) {
			e.printStackTrace();
		}

		// setting the barrier algorithm
		try {
			cplexSolver.setParam(IloCplex.IntParam.RootAlg, IloCplex.Algorithm.Barrier);
		} catch (IloException e1) {
			e1.printStackTrace();
		}

		return stringBuffer.toString();
	}

	public CplexDataHolder getPlacement() {
		String METHOD = "getPlacement";

		model.generate();

		try {

			// Before solving the problem set up for debugging if debug on.
			// ------------------------------------------------------------
            if (CplexAdapter.COLLECT_CPLEX_FILES_TO_FILE) {
				String pathName = CplexAdapter.DIRECTORY_PATH; 

				if (pathName != null) {
					try {
						String fileIndexString = getFileIndexString();

						String exportModelFileName = "cplexModel_" + fileIndexString + ".sav";
						String paramFileName       = "cplexParam_" + fileIndexString + ".txt";
						String outName             = "cplexOut_"   + fileIndexString + ".txt";

						java.io.File             file = new java.io.File(pathName, outName);
						java.io.FileOutputStream fos  = new java.io.FileOutputStream(file);

						cplexSolver.exportModel(pathName + exportModelFileName);
						cplexSolver.writeParam(pathName  + paramFileName);
						cplexSolver.setOut(fos);
					} catch (Exception e) {
						sLOGGER.info("Exception: " + e.toString());            
					}
				} else { 
					sLOGGER.info(METHOD + " has a null pathName returned! ");            
				}
			}

			if (cplexSolver.solve()) {
				sLOGGER.info("---------------------------------------------");
				sLOGGER.info(" Solver status is " + cplexSolver.getStatus());
				sLOGGER.info("---------------------------------------------");

				IloIntMap solutionMatrix = model.getElement("targetPlacement").asIntMap();
				
				IloIntMap targetActiveHostArray = model.getElement("targetActiveHost").asIntMap();
				
				IloNumMap cpuAllocation = model.getElement("cpu_allocation").asNumMap();

				//				IloNumMap vmRelocated = model.getElement("vmRelocated").asNumMap();


//				Double totalRelocationCost = model.getElement("totalRelocationCost").asNum();
//				Double minUtility = model.getElement("minUtility").asNum();
//				Double emptyHosts = model.getElement("emptyHosts").asNum();
//				Double capacityOverFlow = model.getElement("totalOverCapacityCost").asNum();
//
//				Double allocationReward = model.getElement("allocationReward").asNum();
//				Double vmPlacementGlobalGoal = model.getElement("vmPlacementGlobalGoal").asNum();
//				Double sumPlacementPriority = model.getElement("sumPlacementPriority").asNum();
//				IloIntMap vmContainedHost = model.getElement("vmContainedHost").asIntMap();				
//
//				Integer REWARD_WEIGHT            = model.getElement(CplexDataSource.REWARD_WEIGHT_NAME).asInt();
//				Integer PLACEMENT_WEIGHT         = model.getElement(CplexDataSource.PLACEMENT_WEIGHT_NAME).asInt();
////				Integer MIN_UTILITY_WEIGHT       = model.getElement(CplexDataSource.MIN_UTILITY_WEIGHT_NAME).asInt();
//				Integer RELOCATION_WEIGHT        = model.getElement(CplexDataSource.RELOCATION_WEIGHT_NAME).asInt();
//				Integer ENERGY_WEIGHT            = model.getElement(CplexDataSource.ENERGY_WEIGHT_NAME).asInt();
//				Integer CAPACITY_OVERFLOW_WEIGHT = model.getElement(CplexDataSource.CAPACITY_OVERFLOW_WEIGHT_NAME).asInt();
//
//				sLOGGER.info( " ### EpGap = "        + cplexSolver.getParam(IloCplex.DoubleParam.EpGap));
//				sLOGGER.info( " ### EpAGap = "      + cplexSolver.getParam(IloCplex.DoubleParam.EpAGap));
//				sLOGGER.info("  ### IntSolLim = " + cplexSolver.getParam(IloCplex.IntParam.IntSolLim));
//				sLOGGER.info("  ### TiLim = " + cplexSolver.getParam(IloCplex.DoubleParam.TiLim));
//				sLOGGER.info("  ### NodeLim = " + cplexSolver.getParam(IloCplex.IntParam.NodeLim));
//				sLOGGER.info("\n  ### Node file related parameters:");
//				sLOGGER.info("  ### WorkMem = " + cplexSolver.getParam(IloCplex.DoubleParam.WorkMem));
//				sLOGGER.info("  ### TreLim = " + cplexSolver.getParam(IloCplex.DoubleParam.TreLim));
//				sLOGGER.info("  ### NodeFileInd = " + cplexSolver.getParam(IloCplex.IntParam.NodeFileInd));
//				sLOGGER.info("  ### WorkDir = " + cplexSolver.getParam(IloCplex.StringParam.WorkDir));
//				sLOGGER.info("  ### Threads = " + cplexSolver.getParam(IloCplex.IntParam.Threads));
//
//				sLOGGER.info("\n  ### Following are the values of the various calibrated sub-goals:" );
//				sLOGGER.info( " ### allocationReward=" + allocationReward);
//				sLOGGER.info( " ### vmPlacementGlobalGoal=" + vmPlacementGlobalGoal);
//				sLOGGER.info( " ### minUtility=" + minUtility);
//				sLOGGER.info( " ### totalRelocationCost=" + totalRelocationCost);
//				sLOGGER.info( " ### emptyHosts=" + emptyHosts);
//				sLOGGER.info( " ### capacityOverFlow=" + capacityOverFlow);
//
//				sLOGGER.info( " ### ");
//				sLOGGER.info("  ### REWARD GOAL " +  REWARD_WEIGHT * allocationReward);
//				sLOGGER.info("  ### PLACEMENT  GOAL " +  PLACEMENT_WEIGHT * vmPlacementGlobalGoal );
//				sLOGGER.info("  ### RELOCATION GOAL " +  RELOCATION_WEIGHT * totalRelocationCost);
////				sLOGGER.info("  ### MIN UTILITY_GOAL " +  MIN_UTILITY_WEIGHT * minUtility);
//				sLOGGER.info("  ### ENERGY_WEIGHT " +  ENERGY_WEIGHT);
//				sLOGGER.info("  ### ENERGY_GOAL " +  ENERGY_WEIGHT * emptyHosts);
//				sLOGGER.info("  ### CAPACITY_OVERFLOW_GOAL " +  CAPACITY_OVERFLOW_WEIGHT * capacityOverFlow);
//				sLOGGER.info( " ### ");
//
//				sLOGGER.info(" =============> totalPlacementPriority = " + sumPlacementPriority);

				if (CplexAdapter.COLLECT_CPLEX_FILES_TO_FILE) {
					IloIntMap changeMatrix = model.getElement("changeMatrix").asIntMap();
					IloIntMap previouslyPlaced = model.getElement("previouslyPlaced").asIntMap();					
					IloNumMap relocationCost = model.getElement("relocationCost").asNumMap();
					IloIntMap emptyHost = model.getElement("emptyHost").asIntMap();

//					printIntTab("placementPriority", placementPriority);
//					printIntIntMatrix("Non 0 changeMatrix", changeMatrix, true);
					printIntTab("previouslyPlaced", previouslyPlaced);
					//					printNumTab("vmRelocated", vmRelocated);
					printNumTab("relocationCost", relocationCost);
//					printIntTab("vmContainedHost", vmContainedHost);
					printIntTab("emptyHost", emptyHost);
				}

				//				sLOGGER.info(" =============> sumRelocationCost = " + sumRelocationCost);				

				if (CplexAdapter.COLLECT_CPLEX_FILES_TO_FILE) {
					IloNumMap cpuAllocOnHost = model.getElement("cpu_allocationOnHost").asNumMap();
					IloNumMap cpu_vsMarginOnHost = model.getElement("cpu_vsMarginOnHost").asNumMap();

//					printDoubleMatrix("cpuAllocation", cpuAllocation);
					printNumTab("cpu_allocationOnHost", cpuAllocOnHost);
					printNumTab("cpu_vsMarginOnHost", cpu_vsMarginOnHost);
				}
				CplexDataHolder dataHolder = createPlacementObject( solutionMatrix, cpuAllocation);
				return dataHolder;
			} else {
 			        String msg = "Cplex failed to solve the problem.  Returned status is " + cplexSolver.getStatus();

				sLOGGER.info("=============================================");
				sLOGGER.info("=" + msg );
				sLOGGER.info("=============================================");

				throw new RuntimeException(msg);
			}

		} catch (IloException e) {
			// setScoringData_engineStop();

			e.printStackTrace();
		} finally { 
			// cleanup the CPLEX objects: 
			cplexSolver.end();
			errHandler.end();
			try { 
				errLogger.flush();
				errLogger.close();
			} catch (IOException e) {
				throw new RuntimeException("IOException caught while flushing/closing errLogger!", e);
			}
			model.end();
			model.delete();
			oplFactory.end();
		}
		return new CplexDataHolder(nbVms);
	}

//	private void printDoubleMatrix(String string, IloNumMap cpuAllocation) {
//		PhysicalEntity[] PEs = environment.getPhysicalConfiguration().getAllPEs().toArray(new PhysicalEntity[0]);
//		VirtualEntity[] VEs = environment.getVirtualConfiguration().getAllVEs().toArray(new VirtualEntity[0]);
//
//		try {
//			for (int vmIndex = 0; vmIndex < VEs.length; vmIndex++) {
//				for (int hostIndex = 0; hostIndex < PEs.length; hostIndex++) {
//					double allocation;
//					allocation = cpuAllocation.getSub(vmIndex + 1).get(hostIndex + 1);
//					sLOGGER.info(" " + string + "[" + vmIndex + "][" + hostIndex + "]=" + allocation );
//				}
//			}
//		} catch (IloException e) {
//			e.printStackTrace();
//			throw new RuntimeException(e);
//		}
//	}

//	private void printIntIntMatrix(String string, IloIntMap intMatrix, boolean nonZeroOnly) {
//		PhysicalEntity[] PEs = environment.getPhysicalConfiguration().getAllPEs().toArray(new PhysicalEntity[0]);
//		VirtualEntity[] VEs = environment.getVirtualConfiguration().getAllVEs().toArray(new VirtualEntity[0]);
//
//		try {
//			for (int vmIndex = 0; vmIndex < VEs.length; vmIndex++) {
//				for (int hostIndex = 0; hostIndex < PEs.length; hostIndex++) {
//					int intValue;
//					intValue = intMatrix.getSub(vmIndex + 1).get(hostIndex + 1);
//					if (nonZeroOnly && intValue != 0)
//						sLOGGER.info(" " + string + "[" + vmIndex + "][" + hostIndex + "]=" + intValue );
//				}
//			}
//		} catch (IloException e) {
//			e.printStackTrace();
//			throw new RuntimeException(e);
//		}
//	}


	private void printIntTab(String prefixString, IloIntMap tab) {
		try {
			for (int j = 0; j < tab.getSize(); j++) {
				sLOGGER.info(" " + prefixString + "[" + j + "]=" + tab.get(j + 1) );
			}
		} catch (IloException e) {
			throw new RuntimeException(e);
		}
	}

	private void printNumTab(String prefixString, IloNumMap tab) {
		try {
			for (int j = 0; j < tab.getSize(); j++) {
				sLOGGER.info(" " + prefixString + "[" + j + "]=" + tab.get(j + 1) );
			}
		} catch (IloException e) {
			throw new RuntimeException(e);
		}
	}

	// THIS SHOULD BE TRANSFORMED TO FIT THE SPECIFIC PLACEMENT 
	private CplexDataHolder createPlacementObject( IloIntMap solutionMatrix, IloNumMap cpuAllocation)
			throws IloException {

		int[][] curPlacement = new int[nbVms][nbHosts] ;
		int[] curActiveHosts = new int[nbHosts];
		
//		Set<VirtualEntity> ves = environment.getVirtualConfiguration().getAllVEs();
//
//		List<VirtualEntity> veList = new ArrayList<VirtualEntity>(ves);
//
//		HashMap<VirtualEntityID, ResourceValues> reservations = buildReservationsMap(veList, adviceRepository);
//
//		PhysicalEntity[] PEs = environment.getPhysicalConfiguration().getAllPEs().toArray(new PhysicalEntity[0]);
//
//		VirtualEntity[] VEs = environment.getVirtualConfiguration().getAllVEs().toArray(new VirtualEntity[0]);
//
//		sLOGGER.info("Physical envs: " + PEs.length);
//		sLOGGER.info("Virtual envs: " + VEs.length);
//		sLOGGER.info("solutionMatrix->\n" + solutionMatrix);
//		sLOGGER.info("cpuAllocation->\n" + cpuAllocation);

		// creating the placement elements
		for (int vmIndex = 0; vmIndex < nbVms; vmIndex++) {
			IloIntMap tempVSPlacement = solutionMatrix.getSub(vmIndex + 1);

			for (int hostIndex = 0; hostIndex < nbHosts; hostIndex++) {
				if (tempVSPlacement.get(hostIndex + 1) == 1) {

//					double allocation = cpuAllocation.getSub(vmIndex + 1).get(hostIndex + 1);
//					ResourceValues reservation = reservations.get((VirtualEntityID) VEs[vmIndex].getID());
//					reservation = reservation.setValue(ResourceType.CPU, 0L);  // we do not put the CPU allocated in the pels since their values are subject to be changed

//					sLOGGER.info("Allocation for veId=" + VEs[vmIndex].getID() + " -> " + allocation);
//					SAPlacementElement placementElement = new SAPlacementElement(
//							(VirtualEntityID) VEs[vmIndex].getID(),
//							(PhysicalEntityID) PEs[hostIndex].getID(), 
//							reservation
//							);

//					placement.addPlacementElement(true, placementElement);
					curPlacement[vmIndex][hostIndex] = 1;
					//TODO: need to take the real value from Cplex, once it will be done.
					curActiveHosts[hostIndex] = 1;
				}
			}
		}
		return new CplexDataHolder(curPlacement,curActiveHosts) ;
	}
	
	/**
	 * @return
	 */
//	private Properties getCplexParams() {
//
//		Properties cplexProps = new Properties();
////		Properties props = Configuration.getInstance().getServiceConfigProperties();
//
//		for (Object nextKey : props.keySet()) {
//			String key = (String)nextKey;
//			if (key != null && key.startsWith(CPLEX_OPT_PARAM_PREFIX)) {
//				String shortKey = key.substring(CPLEX_OPT_PARAM_PREFIX.length());
//				String val = (String) props.get(key);
//				if (val != null)  { 
//					cplexProps.put(shortKey,  val);
//				}
//			}
//		}
//
//		return cplexProps;
//	}


//	@SuppressWarnings("unused")
//	private Map<String, Float> getFloatParams() {
//
//		Map<String, Float> floatMap = new HashMap<String, Float>();
////		Properties props = Configuration.getInstance().getServiceConfigProperties();
//
//		for (Object nextKey : props.keySet()) {
//			if (nextKey instanceof String) {
//				String key = (String)nextKey;
//				if (key != null && key.startsWith(CPLEX_OPT_PARAM_PREFIX)) {
//					String theKey = key.substring(CPLEX_OPT_PARAM_PREFIX.length());
//					String val = (String) props.get(nextKey);
//					try { 
//						Integer.parseInt(val);
//						// If we get here, this means that val is an integer, we therefore skip it
//					} catch (NumberFormatException e) {
//						// not an integer.  Let's try to see if it is a float:
//						try { 
//							floatMap.put(theKey, Float.parseFloat(val));
//						} catch (Exception ex) {
//							// not a float either, we skip
//						}
//					}
//				}
//			}
//		}
//
//		return floatMap;
//	}

	/**
	 * Sets the CPLEX params to the values retrieved within passed parameters map
	 * @param cplexParams the parameters map
	 */
	private void setCplexParams(Properties cplexParams) {
		// TODO use reflection here:
		for (Object nextKey : cplexParams.keySet()) {
			String nextParam = (String)nextKey;
			try { 
				if ("EpGap".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.DoubleParam.EpGap, getDouble((String)cplexParams.get(nextParam))); // Relative relaxation
				} else if ("WorkMem".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.DoubleParam.WorkMem, getDouble( (String)cplexParams.get(nextParam))); // Absolute relaxation
				} else if ("EpAGap".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.DoubleParam.EpAGap, getDouble( (String)cplexParams.get(nextParam))); // Absolute relaxation
				} else if ("TreLim".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.DoubleParam.TreLim, getDouble( (String)cplexParams.get(nextParam))); 
				} else if ("TuningTiLim".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.DoubleParam.TuningTiLim,  getDouble( (String)cplexParams.get(nextParam)));
				} else if ("TiLim".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.DoubleParam.TiLim,  getDouble( (String)cplexParams.get(nextParam)));
				} else if ("IntSolLim".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.IntParam.IntSolLim,  getInteger( (String)cplexParams.get(nextParam))); 
				} else if ("NodeLim".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.IntParam.NodeLim, getInteger( (String)cplexParams.get(nextParam)));
				} else if ("ItLim".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.IntParam.ItLim, getInteger( (String)cplexParams.get(nextParam)));
				} else if ("NodeFileInd".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.IntParam.NodeFileInd, getInteger( (String)cplexParams.get(nextParam)));
				} else if ("NodeSel".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.IntParam.NodeSel, getInteger( (String)cplexParams.get(nextParam)));
				} else if ("WorkDir".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.StringParam.WorkDir,  (String)cplexParams.get(nextParam));
				} else if ("Threads".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.IntParam.Threads,  getInteger( (String)cplexParams.get(nextParam)));
				} else if ("dataCheck".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.BooleanParam.DataCheck,  getBoolean( (String)cplexParams.get(nextParam)));
				} else if ("Probe".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.IntParam.Probe,  getInteger( (String)cplexParams.get(nextParam)));
				} else if ("CoeRedInd".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.IntParam.CoeRedInd,  getInteger( (String)cplexParams.get(nextParam)));
				} else if ("PreInd".equals(nextParam)) {
					cplexSolver.setParam(IloCplex.BooleanParam.PreInd, getBoolean( (String)cplexParams.get(nextParam)));			
				} else {
					sLOGGER.info(" Float param not recognized! " + nextParam + " with requested value " + cplexParams.get(nextParam));
				}
				
				
				
			} catch (Exception e) {
				sLOGGER.info(" Unexpected exception thrown " + e);
				// skip
			}
		}
	}

	public static String getFileIndexString() {
		String fileIndexString = Integer.valueOf(fileIndex).toString();
		if (fileIndex < 10) {
			fileIndexString = "000" +  fileIndexString;
		} else if (fileIndex < 100) {
			fileIndexString = "00" +  fileIndexString;
		} else if (fileIndex < 1000) {
			fileIndexString = "0" +  fileIndexString;
		} 

		return fileIndexString;
	}

//	protected HashMap<VirtualEntityID, ResourceValues> buildReservationsMap(
//			List<VirtualEntity> veList, AdviceRepository adviceRepository) {
//		HashMap<VirtualEntityID, ResourceValues> resMap = new HashMap<VirtualEntityID, ResourceValues>();
//
//		ResourceValues reservation;
//		for (VirtualEntity nextVe : veList) {
//			reservation = SAAdviceUtil.getResourceValues(nextVe.getID(), adviceRepository, true, AdviceElementType.MIN_DEMAND_AE);
//			resMap.put((VirtualEntityID) nextVe.getID(), reservation);
//		}
//		return resMap;
//	}
//	
	private Integer getInteger(String value) {
		try {
			return Integer.parseInt(value);
		} catch (NumberFormatException nfe) {
			// skip this value
			sLOGGER.info(" Supposed integer value " + value + " ignored");
			throw new NumberFormatException(value);
		}
	}

	private Boolean getBoolean(String value) {
		// The boolean returned represents the value true if:
		// 1. the string argument is not null 
		// 2. is equal, ignoring case, to the string "true". 
		return Boolean.parseBoolean(value);
	}

	private double getDouble(String value) {
		try {
			return Double.parseDouble(value);
		} catch (NumberFormatException nfe) {
			try { 
				Float resFloat = Float.parseFloat(value);
				return 1.0d * resFloat;
			} catch (NumberFormatException nfe2) {
				try {
					int res = Integer.parseInt(value);
					return 1.0d * res;
				} catch (Exception e) {
					// skip this value
					sLOGGER.info(" Value " + value + " ignored");
					throw new NumberFormatException(value);
				}
			}
		}
	}


	/**
	 * Internal class for directing CPLEX errors to the configured logger 
	 * @author erezh
	 */
	protected static class CplexErrorLogger extends OutputStream {

		private StringBuffer sb = new StringBuffer();
		
		@Override
		public void close() throws IOException {
			sLOGGER.info(LOGGER_PREFIX + "close()");
			super.close();
		}

		static private final String LOGGER_PREFIX = "CplexErrorLogger ==> ";
		static private final String CPLEX_ERROR_DELIMITER = "\n";
		
		@Override
		public void write(byte[] b) throws IOException {

			String s = new String(b);
			String[] tokens = s.split(CPLEX_ERROR_DELIMITER);
			
			tokens[0] = sb.toString() + tokens[0];
			sb = new StringBuffer();
			
			for (int index = 0; index < tokens.length -1; index++) {
				sLOGGER.info(LOGGER_PREFIX + tokens[index]);
			}

			// Special handling for the last one:
			String last = tokens[tokens.length -1];
			if (s.endsWith(CPLEX_ERROR_DELIMITER)) {
				sLOGGER.info(LOGGER_PREFIX + last);
			} else {
				sb.append(last);
			}
		}

		@Override
		public void write(byte[] b, int off, int len) throws IOException {

			String s = new String(b, off, len);
			sLOGGER.info(LOGGER_PREFIX + "write(buf, off, len): " + s);
		}

		@Override
		public void flush() throws IOException {

			sLOGGER.info(LOGGER_PREFIX + "flush() ");
		}

		@Override
		public void write(int b) throws IOException {
			byte[] ba = new byte[1];
			ba[0] = (byte)b;
			
			String s = new String(ba);
			sLOGGER.info(LOGGER_PREFIX + "write(byte): " + s);
		}
	}



}


